<template>
  <div>
    <div class="mainStyle history-box" v-loading="waitLoading">
      <!-- <span v-html="testFn(test)"></span> -->
      <history @handle-history="handleHistory" ref="history"></history>
      <div class="contentRight columnFlex">
        <div class="pos-line" v-if="role !== '游客'">
          <el-button size="small" @click="adjustmentRangeDialog = true" style="margin-right: 10px"
            >调整范围</el-button
          >
        </div>
        <div class="chatBox chatBox-2" ref="chatBox" :class="{ 'chatBox-1': showLimit }">
          <div class="leftBox">
            <img src="@/assets/image/robot.png" class="userIcon" />
            <div class="msgtext">您好！</div>
            <!-- <span v-html="testFn(test)"></span> -->
          </div>
          <div
            v-for="(message, index) in messages"
            :key="index"
            :class="index % 2 == 0 ? 'rightBox' : 'leftBox'"
          >
            <img v-if="index % 2 != 0" src="@/assets/image/robot.png" class="userIcon" />

            <div class="msgtext">
              <p v-html="message.text" v-if="!message.html"></p>
              <p v-html="message.html" v-if="message.html"></p>
              <div v-if="index % 2 !== 0 && save_topk_paragraphs[index]" class="provenance-item">
                <div @click="save_topk_paragraphs[index].show = !save_topk_paragraphs[index].show">
                  知识库匹配结果
                  <i
                    class="el-icon-arrow-down icon-item"
                    v-if="!save_topk_paragraphs[index].show"
                  ></i>
                  <i class="el-icon-arrow-up icon-item" v-if="save_topk_paragraphs[index].show"></i>
                </div>
                <div
                  v-for="(item, index2) in save_topk_paragraphs[index].arr"
                  :key="'msg' + index2"
                >
                  <template v-if="save_topk_paragraphs[index].show">
                    <p>
                      <span class="title-item" @click="previewPdf(item.file_id)"
                        >引用{{ index2 + 1 }}：{{ item.label }}</span
                      >
                    </p>
                    <p class="content-container">
                      <span class="content-item" v-html="item.content"></span>
                    </p>
                  </template>
                </div>
              </div>
            </div>
            <img v-if="index % 2 == 0" src="@/assets/image/user.png" class="userIcon" />
            <el-button
              v-if="message.show"
              type="primary"
              size="mini"
              class="score"
              @click.stop="showCommit(message, index)"
              ><svg-icon iconClass="chatScore" class="chatScore"></svg-icon>人工纠偏</el-button
            >
            <el-button
              v-if="message.show"
              size="mini"
              class="score2"
              @click="copyConent(message, index)"
              >一键copy</el-button
            >
          </div>
        </div>
        <div class="chatInput">
          <div v-if="chatInput && selectType == 2 && seachFlag" class="searchResult">
            <i
              class="el-icon-close"
              style="position: absolute; top: 12px; right: 12px; font-size: 20px; cursor: pointer"
              @click="seachFlag = false"
            ></i>
            <div v-if="searchFileList.length > 0" class="searchResultbox">
              <div class="fileItem" v-for="(item, index) in searchFileList" :key="index">
                <span @click="previewPdf(item.file_id)"> {{ item.file_name }}</span>
              </div>
            </div>
            <div
              style="
                box-sizing: border-box;
                padding: 6px;
                justify-content: center;
                height: 100%;
                display: flex;
                align-items: center;
              "
              v-else="searchFileList.length == 0"
            >
              未查询到相关文件
            </div>
          </div>
          <el-input
            @keyup.enter.native="handleSubmit"
            @input="getValue"
            v-model="chatInput"
            :placeholder="selectType == 1 ? '请输入提问内容' : '请输入搜索关键字'"
            class="input-with-select"
          >
          </el-input>
          <el-button type="primary" class="sendBtn" @click.native="handleSubmit">{{
            selectType == 1 ? '发送' : '搜索'
          }}</el-button>
        </div>
      </div>
      <el-dialog
        width="40%"
        class="warn-detail-bg"
        title="人工纠偏"
        :visible.sync="commitShow"
        :close-on-click-modal="false"
        :modal-append-to-body="false"
      >
        <div class="headerIcon">
          <svg-icon iconClass="chatScore"></svg-icon>
        </div>
        <div class="fault-dialog-body">
          <el-form class="radioForm" ref="commitForm" label-width="100px" :model="commitForm">
            <!-- <el-form-item style="width: 90%" label="评分:">
            <el-rate v-model="commitForm.score"></el-rate>
          </el-form-item> -->
            <el-form-item style="width: 90%" label="Q:">
              {{ commitForm.score }}
            </el-form-item>
            <el-form-item style="width: 90%" label="A:">
              <el-input
                type="textarea"
                class="textArea"
                :rows="10"
                v-model="commitForm.comment"
                placeholder="请输入内容"
              ></el-input>
            </el-form-item>
          </el-form>
        </div>
        <template #footer>
          <div class="dialog-footer">
            <el-button class="confirm-btn" @click="commitShow = false">取 消</el-button>
            <el-button type="primary" @click="commit">确 定</el-button>
          </div>
        </template>
      </el-dialog>
      <el-dialog
        top="10px"
        width="60%"
        class="warn-detail-bg"
        title="文件预览"
        :visible.sync="preShow"
        :close-on-click-modal="false"
        :modal-append-to-body="false"
      >
        <div class="markBg">
          <pdfPreview :key="pdfUrl" v-if="typeValue == 1" :pdfUrl="pdfUrl"></pdfPreview>
          <div class="mdbox" v-if="typeValue == 2">
            <div ref="mdViewer" class="mdviewer" :key="keyValue" v-html="markdownContent"></div>
            <!-- <canvas ref="mdCanvas" class="canvasBox"></canvas> -->
          </div>
          <div class="imgviewer" v-if="typeValue == 3">
            <img :src="imageUrl" alt="" />
          </div>
        </div>
        <template #footer>
          <div class="dialog-footer">
            <el-button class="confirm-btn" @click="preShow = false">关 闭</el-button>
          </div>
        </template>
      </el-dialog>
      <el-dialog
        top="10px"
        width="60%"
        title="调整范围"
        :visible.sync="adjustmentRangeDialog"
        :close-on-click-modal="false"
        :modal-append-to-body="false"
        :show-close="false"
      >
        <div class="markBg">
          <div class="pos-container">
            <el-form ref="form" :model="form" label-width="80px">
              <el-form-item label="目录范围">
                <el-tree
                  :data="treeData"
                  ref="treeRef"
                  node-key="id"
                  show-checkbox
                  default-expand-all
                  @check-change="handleCheckChangeObj"
                  :expand-on-click-node="false"
                >
                  <span class="custom-tree-node" slot-scope="{ node, data }">
                    <span style="margin-right: 20px">{{ node.label }}</span>
                  </span>
                </el-tree>
              </el-form-item>
              <el-form-item label="文件范围">
                <div v-for="item in selectData" class="item" :key="item.name">
                  <p class="item-title">目录：{{ item.name }}</p>
                  <el-button size="small" @click="selectAll(item)">全选</el-button>
                  <el-button size="small" @click="selectReverse(item)">反选</el-button>
                  <el-checkbox-group v-model="item.selected" v-if="item.opitons.length !== 0">
                    <el-checkbox
                      class="checkbox-item"
                      v-for="item2 in item.opitons"
                      :key="item2.id"
                      :label="item2.id"
                      :name="item2.id"
                      >{{ item2.name }}</el-checkbox
                    >
                  </el-checkbox-group>
                </div>
              </el-form-item>
            </el-form>
          </div>
        </div>
        <template #footer>
          <div class="dialog-footer">
            <el-button class="confirm-btn" @click="clearBtn()">取消</el-button>
            <el-button class="confirm-btn" type="primary" @click="save()">确定</el-button>
          </div>
        </template>
      </el-dialog>
    </div>
  </div>
</template>

<script>
import { getData, postData } from '@/service/getData';
import axios from 'axios';
import baseUrl from '../../service/env.js';
import { fetchEventSource } from '@microsoft/fetch-event-source';
import pdfPreview from '@/components/common/pdfPreview.vue';
import marked from 'marked';
import history from '../../components/history.vue';

export default {
  components: {
    pdfPreview,
    history,
  },
  data() {
    return {
      chat_id: null,
      selectData: [],
      test: '\n\n```markdown\n在信号系统中，ATP通常指**列车自动保护系统**（Automatic Train Protection），其核心功能包括：\n1. **安全限速控制**：实时监测列车运行速度，确保不超过线路或信号允许的最高限速；\n2. **防碰撞保护**：通过计算列车位置与前方障碍物的安全距离，触发紧急制动避免追尾；\n3. **运行模式管理**：与联锁系统、车载控制设备联动，强制执行安全驾驶规则；\n4. **故障导向安全**：在检测到异常时（如通信中断、设备故障），自动采取降级运行或停车措施。\n\n实现方式包括基于轨道电路、无线通信（如CBTC）或应答器的信息传输，广泛应用于铁路、地铁等轨道交通领域。\n```',
      adjustmentRangeDialog: false,
      uploadParams: {
        uploadUrl: '/agent/corrector/upload_original_file',
        data: {},
        headers: {
          Authorization: '',
        },
        name: 'file',
        fileLists: [],
      },
      form: {
        search_str: '',
        folder_ids: [],
        file_ids: [],
      },

      showLimit: false,
      role: 'user', // admin
      waitLoading: false,
      keyValue: '',
      imageUrl: '',
      pdfUrl: '',
      compiledMarkdown: '',
      preShow: false,
      markdownContent: '',
      messages: [],
      save_topk_paragraphs: [],
      topk_paragraphs: [],
      treeDataTemp: [],
      text: '',
      chatInput: '',
      treeData: [],
      levelOneSel: '',
      files: [],
      commitShow: false,
      currentId: '',
      commitForm: {
        score: 0,
        comment: '',
      },
      link: '',
      showSearch: false,
      SeachList: [],
      SeachListSelect: [],
      selectType: '1',
      searchFileList: [],
      seachFlag: false,
      typeValue: '',
      watermark: '交控科技',
      partition_names: [],
      levelTwoSelList: [],
      thinkTag: false,
      partition_namesList: [],
    };
  },
  mounted() {
    this.role = this.$store.state.user.groups[0] ? this.$store.state.user.groups[0].name : '游客';
    let token = localStorage.getItem('token');
    this.uploadParams.headers['Authorization'] = 'Token ' + token;
    this.getTree();
  },
  beforeDestroy() {
    this.removeLinkClickListeners();
  },
  activated() {
    // this.updataTree();
  },
  methods: {
    clearBtn() {
      this.adjustmentRangeDialog = false;
      this.form.file_ids = [];
      this.$refs.treeRef.setCheckedKeys([]);
      this.$message.warning('未选择文件范围');
    },

    save() {
      this.adjustmentRangeDialog = false;
      this.form.file_ids = [];
      this.selectData.forEach((item) => {
        item.selected.forEach((id) => {
          this.form.file_ids.push(parseInt(id));
        });
      });
      if (this.form.file_ids.length == 0) {
        this.$message.warning('未选择文件范围');
      } else {
        this.$message.success('已选择文件范围');
      }
    },
    testFn(val) {
      // 截取字符串中 ```markdown``` 之后的全部
      let newVal = val.substring(val.indexOf('```markdown') + 11);
      newVal = newVal.slice(0, -3);
      console.log('要处理的markdown内容', newVal);
      return marked(newVal);
    },
    testFn2(val) {
      let str = val;
      // 截取字符串中 <h2 class="think"> ..</h2> 之间的内容
      let think = '';
      const startIndex = val.indexOf('<h2 class="think">');
      const endIndex = val.indexOf('</h2>', startIndex + 18);
      if (startIndex !== -1 && endIndex !== -1) {
        think = str.substring(startIndex + 18, endIndex);
      }
      console.log('要处理的内容', str);
      return '<h2 class="think">' + marked(think) + '</h2>';
    },
    handleHistory(obj) {
      this.chat_id = obj.id;
      this.messages = [];
      obj.qapairs.forEach((item) => {
        this.messages.push({
          role: 'user',
          text: item.question,
        });
        this.messages.push({
          role: 'assistant',
          text:
            '<h2 class="think">' + item.think + '</h2>' + '<p>' + this.testFn(item.answer) + '</p>',
        });
      });
    },
    uploadHistoryList() {
      // 调用 history 组件的方法
      this.$refs.history.getHistory();
    },
    handleCheckChangeObj(data, checked, indeterminate) {
      // x
      this.form.file_ids = [];
      let newArr = [];
      const tree = this.$refs.treeRef;
      if (tree) {
        let arr = [];
        let selectedNodes = []; // 获取所有选中的节点
        let nodes = [];
        tree.getCheckedNodes().forEach((item) => {
          arr.push(item.id); // 获取所有选中节点的id
          if (item.files.length > 0) {
            let optionNodes = [];
            let selected = [];
            item.files.forEach((item) => {
              nodes.push({
                name: item.name,
                id: item.id,
              });
              optionNodes.push({
                name: item.name,
                id: item.id.toString(),
              });

              // 获取所有选中节点的对象
              selectedNodes.push(item.id); // 获取所有选中节点的id
              selected.push(item.id.toString());
            });
            newArr.push({
              name: item.name,
              opitons: optionNodes,
              selected: selected,
            });
          }
          // nodes.push(); // 获取所有选中节点的对象
        });
        this.form.folder_ids = arr; // 更新已选择的节点
        // this.form.assign_ids = selectedNodes; // 更新已选择的节点
        this.partition_namesList = nodes;
        this.selectData = newArr;
      }
    },
    handleCheckChange(data, checked, indeterminate) {
      console.log(data, checked, indeterminate);
      this.form.file_ids = []; // 清空已选择的节点
      const tree = this.$refs.treeRef;
      if (tree) {
        let arr = [];
        let selectedNodes = []; // 获取所有选中的节点
        let nodes = [];
        tree.getCheckedNodes().forEach((item) => {
          arr.push(item.id); // 获取所有选中节点的id
          if (item.files.length > 0) {
            item.files.forEach((item) => {
              nodes.push({
                name: item.name,
                id: item.id,
              }); // 获取所有选中节点的对象
              selectedNodes.push(item.id); // 获取所有选中节点的id
            });
          }
          nodes.push(); // 获取所有选中节点的对象
        });
        this.form.folder_ids = arr; // 更新已选择的节点
        this.form.file_ids = selectedNodes; // 更新已选择的节点
        this.partition_namesList = nodes;
      }
    },
    getTree() {
      getData(`api/knowledge_base/files/?user_id=${this.$store.state.user.id}`).then((res) => {
        this.treeData = res;
        // 递归遍历数组，给每个对象添加label属性
        const traverse = (arr) => {
          arr.forEach((item) => {
            item.label = item.name;
            item.id = item.id.toString();
            if (item.children && item.children.length > 0) {
              traverse(item.children);
            }
          });
        };
        traverse(this.treeData);
      });
    },
    copyToClipboardFallback(text) {
      const textarea = document.createElement('textarea');
      textarea.value = text;
      document.body.appendChild(textarea);
      textarea.select();

      try {
        const successful = document.execCommand('copy');
        if (successful) {
          console.log('文本已成功复制到剪贴板');
        } else {
          console.error('无法复制文本');
        }
      } catch (err) {
        console.error('无法复制文本: ', err);
      } finally {
        document.body.removeChild(textarea);
      }
    },
    selectAll(obj) {
      // 全选
      obj.selected = obj.opitons.map((item) => item.id);
    },
    selectReverse(obj) {
      // 反选
      obj.selected = obj.opitons
        .filter((item) => !obj.selected.includes(item.id))
        .map((item) => item.id);
    },
    copyConent(v, n) {
      let str = this.messages[n].text;

      // 去除掉 this.commitForm.comment think标签
      str = str.replace(/<h2 class="think">.*?<\/h2>/g, '');
      // 将str复制到剪切板
      this.copyToClipboardFallback(str);
      this.$message({
        message: '已复制到剪切板',
        type: 'success',
      });
    },
    changeType(v) {
      this.seachFlag = false;
      this.chatInput = '';
    },
    //处理v-html锚点跳转影响页面路由问题
    addLinkClickListeners() {
      const content = this.$refs.mdViewer;
      content.addEventListener('click', this.handleLinkClick);
    },
    removeLinkClickListeners() {
      const content = this.$refs.mdViewer;
      content.removeEventListener('click', this.handleLinkClick);
    },
    handleLinkClick(event) {
      const target = event.target;
      if (target.tagName === 'A' && target.getAttribute('href').startsWith('#')) {
        event.preventDefault();
        const href = target.getAttribute('href');
        if (href) {
          // 处理锚点跳转
          document.querySelector(decodeURIComponent(href)).scrollIntoView({ behavior: 'smooth' });
        }
      }
    },
    //预览pdf
    previewPdf(id) {
      this.$message.info('努力加载中，请稍侯...');
      this.waitLoading = true;
      postData('api/knowledge_base/files/preview_file/', { file_id: id }, 'post', {
        responseType: 'blob',
        Authorization: this.uploadParams.headers['Authorization'],
      })
        .then((res) => {
          console.log(res);
          if (res.type == 'application/pdf') {
            this.typeValue = 1;
            const url = window.URL.createObjectURL(new Blob([res], { type: 'application/pdf' }));
            this.pdfUrl = url;
            this.preShow = true;
          } else if (res.type == 'text/markdown') {
            this.typeValue = 2;
            this.keyValue = 'md' + Math.floor(Math.random() * 1000 + 1);
            const reader = new FileReader();
            reader.onload = (event) => {
              const markdownText = event.target.result;
              // 将 Markdown 转换为 HTML
              this.markdownContent = marked(markdownText);
              this.preShow = true;

              this.$nextTick(() => {
                this.addLinkClickListeners();
                // this.waitForImagesToLoad();
              });
            };
            reader.onerror = (error) => {
              console.error('Error reading Blob:', error);
            };
            reader.readAsText(res, 'UTF-8'); // 指定编码为 UTF-8
          } else if (res.type == 'image/png' || res.type == 'image/jpeg') {
            console.log(res.type);
            this.typeValue = 3;
            const blob = new Blob([res], { type: res.type }); // 根据实际情况设置 MIME 类型
            // 创建临时的 URL
            this.imageUrl = URL.createObjectURL(blob);
            this.preShow = true;
          }
        })
        .catch((e) => {
          this.$message.error('获取文件失败，请稍后重试或联系管理员...');
        })
        .finally((v) => {
          this.waitLoading = false;
        });
    },
    waitForImagesToLoad() {
      const mdViewer = this.$refs.mdViewer;
      if (!mdViewer) return;

      const images = mdViewer.querySelectorAll('img');
      if (images.length === 0) {
        this._renderWatermark();
        return;
      }

      let loadedCount = 0;
      const totalImages = images.length;

      images.forEach((img) => {
        img.onload = () => {
          loadedCount++;
          if (loadedCount === totalImages) {
            this.imagesLoaded = true;
            this._renderWatermark();
          }
        };

        // Handle images that are already complete
        if (img.complete) {
          loadedCount++;
          if (loadedCount === totalImages) {
            this.imagesLoaded = true;
            this._renderWatermark();
          }
        }
      });
    },
    // 在画布上渲染水印
    _renderWatermark() {
      this.$nextTick(() => {
        let canvas = this.$refs.mdCanvas;
        canvas.width = this.$refs.mdViewer.clientWidth;
        canvas.height = this.$refs.mdViewer.clientHeight;
        let ctx = canvas.getContext('2d');
        // 平铺水印
        let pattern = ctx.createPattern(this._initWatermark(), 'repeat');
        ctx.rect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = pattern;
        ctx.fill();
      });
    },

    // 生成水印图片
    _initWatermark() {
      let canvas = document.createElement('canvas');
      canvas.width = 200;
      canvas.height = 200;
      let ctx = canvas.getContext('2d');
      ctx.rotate((-18 * Math.PI) / 180);
      ctx.font = '30px Vedana';
      ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
      ctx.textAlign = 'left';
      ctx.textBaseline = 'middle';
      ctx.fillText(this.watermark, 10, 100);
      return canvas;
    },
    getComment() {
      postData('/get_comment', { id: this.currentId }, 'post', {
        headers: { 'Content-Type': 'application/json;charset=UTF-8', Cookie: '' },
      })
        .then((res) => {
          console.log(res);
          this.commitForm.score = res.rate;
          this.commitForm.comment = res.comment;
        })
        .catch((e) => {
          // this.$message.error('提交失败，请稍后重试...');
        })
        .finally((v) => {
          // this.commitShow = false;
        });
    },

    handleClickSearch(item) {
      console.log('index', index);
      item.showSearch = true;
    },
    //查询关联文件
    calcLink(item, treeData) {
      console.log('item', item, treeData);
      if (!this.link) {
        this.showSearch = false;
        this.SeachList = [];
        this.SeachListSelect = [];
        // this.$message.warning('请输入关键字');
        return;
      }
      item.show = false;
      let arr = item.partitions;
      item.checkList = [];
      this.SeachList = [];
      let num = 0;
      arr.forEach((v) => {
        v.checkList = []; // 初始化值
        v.show = false;
        v.files.forEach((m) => {
          if (m.file_name.indexOf(this.link) != -1) {
            let obj = m;
            obj.file = item.collection_name + '/' + v.partition_name + '/' + m.file_name;
            this.SeachList.push(m);
            this.showSearch = true;
            item.show = true;
            num++;
          } else {
          }
        });
      });
      if (num === 0) {
        item.show = true;
        this.$message.warning('未查询到相关文件');
      }
      this.getFiles();
    },
    //展示评价弹窗

    showCommit(v, n) {
      // 赋值
      this.commitForm.score = this.messages[n - 1].text;
      //  去除掉 think的
      this.commitForm.comment = this.messages[n].text;
      // 去除掉 this.commitForm.comment think标签
      this.commitForm.comment = this.commitForm.comment.replace(/<h2 class="think">.*?<\/h2>/g, '');
      this.currentId = v.id;
      this.commitShow = true;
    },
    //提交评价
    commit() {
      console.log(this.commitForm);
      //if (!this.commitForm.score) {
      //  this.$message.warning('请评分');
      //return;
      //  }
      if (!this.commitForm.comment) {
        this.$message.warning('请评价');
        return;
      }
      postData(
        'api/qa/add_comment/',
        { id: this.currentId, comment: this.commitForm.comment },
        'post',
        {
          headers: { 'Content-Type': 'application/json;charset=UTF-8', Cookie: '' },
        },
      )
        .then((res) => {
          if (res && res.status == 200) {
            this.$message.success('提交成功');
          } else {
            this.$message.warning(res.message);
          }
        })
        .catch((e) => {
          this.$message.error('提交失败，请稍后重试...');
        })
        .finally((v) => {
          this.commitShow = false;
        });
    },
    //激活页面时，更新目录，保持原先选择的文件
    updataTree() {
      postData('/list_tree', {}).then((res) => {
        if (res && res.status == 200) {
          if (this.treeData.length > 0) {
            if (res.tree && Array.isArray(res.tree) && res.tree.length > 0) {
              res.tree?.forEach((item) => {
                const matchingItem = this.treeDataTemp.find(
                  (ite) => item.collection_name === ite.collection_name,
                );

                if (matchingItem) {
                  item.show = matchingItem.show;
                  item.allCheck = matchingItem.allCheck;
                  item.checkList = matchingItem.checkList;
                  if (item.partitions && item.partitions.length > 0) {
                    item.partitions.forEach((it) => {
                      const matchingPartition = matchingItem.partitions.find(
                        (i) => it.partition_name === i.partition_name,
                      );
                      if (matchingPartition) {
                        it.show = matchingPartition.show;
                        it.allCheck = matchingPartition.allCheck;
                        it.checkList = matchingPartition.checkList;
                      }
                    });
                  }
                } else {
                  item.show = false;
                  item.allCheck = false;
                  item.checkList = [];
                  if (item.partitions && item.partitions.length > 0) {
                    item.partitions.forEach((it) => {
                      it.show = false;
                      it.allCheck = false;
                      ite.checkList = [];
                    });
                  }
                }
              });
            }
            this.treeData = res.tree || [];
          } else {
            if (res.tree && Array.isArray(res.tree) && res.tree.length > 0) {
              res.tree?.forEach((item) => {
                item.show = false;
                item.checkList = [];
                item.allCheck = false;
                if (item.partitions && item.partitions.length > 0) {
                  item.partitions.forEach((ite) => {
                    ite.show = false;
                    ite.checkList = [];
                    ite.allCheck = false;
                  });
                }
              });
            }
            this.treeData = res.tree || [];
          }
          this.getFiles();
        }
      });
    },

    //获取选中的文件
    getFiles() {
      let files = [];
      if (!this.showSearch) {
        //
        this.treeData.forEach((item) => {
          item.partitions.forEach((v) => {
            v.checkList.forEach((m) => {
              files.push(item.collection_name + '/' + v.partition_name + '/' + m);
            });
          });
        });
        this.files = files;
      } else {
        // 筛选后
        this.files = this.SeachListSelect;
      }
    },
    getValue() {
      this.seachFlag = false;
    },
    //提问
    handleSubmit() {
      if (this.selectType == 1) {
        this.handleChatSubmit();
      } else if (this.selectType == 2) {
        this.seachTextFile();
      }
    },
    handleChatSubmit() {
      if (this.chatInput) {
        this.messages.push({
          text: this.chatInput,
        });
        let chatInput = this.chatInput;
        this.chatInput = '';

        this.$nextTick(() => {
          let chatBox = this.$refs.chatBox;
          console.log(chatBox.scrollHeight);
          chatBox.scrollTop = chatBox.scrollHeight;
        });
        console.log(this.treeDataTemp);

        setTimeout(() => {
          this.messages.push({
            text: '思考中，请稍候...',
          });
          this.save_topk_paragraphs.push([]);
          this.messages[_this.messages.length - 1].show = false;
          this.$nextTick(() => {
            let chatBox = this.$refs.chatBox;
            chatBox.scrollTop = chatBox.scrollHeight;
          });
        });
        let _this = this;
        let count = 0;
        const controller = new AbortController();
        fetchEventSource('/api/qa/stream_qa/', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json;charset=UTF-8',
            Accept: ['text/event-stream', 'application/json'],
            Authorization: this.uploadParams.headers['Authorization'],
          },
          body: JSON.stringify({
            question: chatInput,
            file_ids: this.form.file_ids,
            folder_ids: [], // this.form.folder_ids,
            chat_id: this.chat_id,
          }),
          openWhenHidden: true,
          signal: controller.signal, //与其相关联的signal属性
          onopen(e, data) {
            console.log(e, data, 'SSE在连接打开时被调用');
            if (e.status == 200) {
              _this.messages[_this.messages.length - 1].text = '<h2 class="think">';
            } else if (e.status == 400) {
              _this.messages[_this.messages.length - 1].text = '问题包含敏感词，无法回答';
            } else {
              _this.messages[_this.messages.length - 1].text = '服务开小差了，请稍后重试';
              _this.$nextTick(() => {
                let chatBox = _this.$refs.chatBox;
                chatBox.scrollTop = chatBox.scrollHeight;
              });
            }
          },
          onmessage(msg, event, error) {
            console.log('收到消息:', msg, error, event);
            if (msg.event === 'id') {
              _this.messages[_this.messages.length - 1].id = msg.data;
              _this.messages[_this.messages.length - 1].html =
                _this.testFn2(_this.messages[_this.messages.length - 1].text) +
                _this.testFn(_this.messages[_this.messages.length - 1].text);
              _this.uploadHistoryList();
            }
            if (msg.event === 'chat_id') {
              _this.chat_id = msg.data;
            }
            //
            if (msg.event === 'answer') {
              const res = msg.data;
              if (res === '' && count === 0) {
                count = 1;
              }
              if (res === '' && count === 1) {
                count = 2;
              } else {
                count = 0;
              }

              // 判断返回值 是否是 </think> 结尾 如果是的化 证明
              if (res === '</think>') {
                _this.messages[_this.messages.length - 1].text += '</h2>';
              } else {
                _this.messages[_this.messages.length - 1].text += res;
              }

              _this.$nextTick(() => {
                let chatBox = _this.$refs.chatBox;
                chatBox.scrollTop = chatBox.scrollHeight;
              });
            } else if (msg.event === 'reference') {
              let obj = JSON.parse(msg.data);
              obj.forEach((item) => {
                _this.topk_paragraphs.push({
                  label: item.file_name,
                  content: marked(item.page_content),
                  rank: item.rank,
                  file_id: item.file_id,
                  show: false,
                });
              });
            }
          },
          onclose(e, msg, event) {
            _this.save_topk_paragraphs.push({ show: false, arr: _this.topk_paragraphs });
            _this.topk_paragraphs = [];
            if (_this.messages[_this.messages.length - 1].id) {
              _this.messages[_this.messages.length - 1].show = true;
            }
            controller.abort();
            _this.$forceUpdate();
          },
          onerror(err) {
            _this.messages[_this.messages.length - 1].text = '服务开小差了，请稍后重试';
            _this.$nextTick(() => {
              let chatBox = _this.$refs.chatBox;
              chatBox.scrollTop = chatBox.scrollHeight;
            });
            console.log(err, 'onerror');
            controller.abort();
          },
        });
      }
    },
    //二级目录全选、取消全选
    checkAllPart(isAll, index) {
      let arr = this.treeData[index].partitions || [];
      this.treeData[index].checkList = isAll ? arr.map((item) => item.partition_name) : [];
      this.treeDataTemp = JSON.parse(JSON.stringify(this.treeData));
      this.treeData[index].partitions.forEach((v) => {
        if (isAll) {
          v.show = true;
          v.allCheck = true;
          v.checkList = [];
          v.files.forEach((m) => {
            v.checkList.push(m.file_name);
          });
        } else {
          v.allCheck = false;
          v.checkList = [];
          v.show = false;
        }
      });
      this.getFiles();
    },
    //二级目录单独选中/取消选中
    handleCheckedPartsChange(val, index, ind) {
      this.treeData[index].allCheck = this.treeData[index].partitions.length === val.length;
      if (val.includes(this.treeData[index].partitions[ind].partition_name)) {
        this.treeData[index].partitions[ind].show = true;
        this.treeData[index].partitions[ind].allCheck = true;
        this.treeData[index].partitions[ind].checkList = [];
        this.treeData[index].partitions[ind].files.forEach((m) => {
          this.treeData[index].partitions[ind].checkList.push(m.file_name);
        });
      } else {
        this.treeData[index].partitions[ind].show = false;
        this.treeData[index].partitions[ind].allCheck = false;
        this.treeData[index].partitions[ind].checkList = [];
      }
      this.treeDataTemp = JSON.parse(JSON.stringify(this.treeData));
      this.getFiles();
    },
    //三级目录全选、取消全选
    checkeAllFile(isAll, index, ind) {
      let arr = this.treeData[index].partitions[ind].files || [];
      this.treeData[index].partitions[ind].checkList = isAll
        ? arr.map((item) => item.file_name)
        : [];
      this.treeDataTemp = JSON.parse(JSON.stringify(this.treeData));
      this.getFiles();
    },
    //三级目录单独选中/取消选中
    handleCheckedFilesChange(val, index, ind) {
      this.treeData[index].partitions[ind].allCheck =
        this.treeData[index].partitions[ind].files.length === val.length;
      this.treeDataTemp = JSON.parse(JSON.stringify(this.treeData));
      this.getFiles();
    },

    // 关联选择
    handleCheckedFilesChangeLink(val) {
      this.getFiles();
    },

    //一级目录点击事件
    levelOneClick(item, index) {
      if (this.levelOneSel != item.collection_name) {
        this.levelOneSel = item.collection_name;
        this.treeData?.forEach((item) => {
          item.show = false;
          item.allCheck = false;
          item.checkList = [];
          if (item.partitions && item.partitions.length > 0) {
            item.partitions.forEach((ite) => {
              ite.show = false;
              ite.allCheck = false;
              ite.checkList = [];
            });
          }
        });
        this.treeDataTemp = JSON.parse(JSON.stringify(this.treeData));
        this.getFiles();
      }
      item.show = !item.show;
    },
  },
};
</script>

<style lang="scss" scoped>
.item {
  display: block !important;
}

.line {
  width: 100%;
  display: block;
  margin: 4px 0;
}

.provenance-item {
  border: 1px solid #354f8a;
  border-radius: 4px;
  font-size: 14px;
  line-height: 24px;
  padding: 2px;
  margin-bottom: 20px;
  cursor: pointer;
}

.icon-item {
  float: right;
}

.title-item {
  text-decoration: underline;
}

.content-item {
  color: #b3b9c4;
}
</style>
<style>
.warn-detail-bg .el-textarea__inner {
  height: auto !important;
}
.content-container table {
  width: 100%;
  border-top: 1px solid #2a548a !important;
  border-left: 1px solid #2a548a !important;
}

.content-container table td,
.content-container table th {
  border-bottom: 1px solid #2a548a !important;
  border-right: 1px solid #2a548a !important;
  font-size: 12px;
}

.content-container img {
  max-width: 100%;
}

.input-with-select .el-input-group__prepend {
  background-color: transparent;
  border: none;
  width: 4vw;
  margin-right: 4px;

  .el-input__inner {
    background-color: transparent;
    border: 2px solid #1640a4;
    border-top-left-radius: 6px;
    border-bottom-left-radius: 6px;
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;

    &:hover,
    &:active,
    &:focus {
      border: 2px solid #1640a4;
      color: #ffffff;
    }
  }
}
.content-item h1,
h2,
h3,
h4,
h5,
h6 {
  font-size: 14px;
  padding: 0;
  margin: 0;
}
.content-item p {
  font-size: 14px;
  padding: 0;
  margin: 0;
}
.msgtext h1 {
  font-size: 14px;
  font-weight: normal;
}
.think {
  font-weight: normal;
  color: #7d93bb;
  padding-bottom: 10px;
  border-bottom: 1px solid #5893ff3b;
  margin-bottom: 10px;
}
.pos-line {
  padding: 10px;
  background: #fff;
  width: calc(100% - 20px);
  margin: 0px 0 10px 10px;
  box-sizing: border-box;
  border-radius: 6px;
}
.checkbox-container {
  margin-top: 10px;
  font-size: 12px;
  display: block;
}
.mainStyle .columnFlex .chatBox-2 {
  max-height: calc(100vh - 320px) !important;
}
.mainStyle .columnFlex .chatBox-1 {
  max-height: calc(100vh - 500px) !important;
}

.history-box {
  display: grid;
  grid-template-columns: 180px 1fr;
}
.item {
  background: #f7f7f7;
  margin: 10px 0;
  padding: 10px;
}
.item-title {
  color: #21b5e2;
  padding-bottom: 10px;
  border-bottom: 1px solid #21b5e2;
}
</style>
